iT邦幫忙

2021 iThome 鐵人賽

DAY 22
3

前面介紹了 git merge 指令合併分支,本篇就來介紹另一種方式: Rebase


從 Rebase 字面來看,是 re 加上 base ,可以理解成「重新定義分支的參考基準」。

使用 git rebase 指令等於是修改歷史,他會使分支移動到不同的 Commit 重新定義基準點。

git rebase 指令與 git merge 指令最大的差異是什麼呢?

👉 git rebase 指令不會額外產生新的 Commit 來合併兩個分支。

先從以下範例來看整個關係圖:

假設現在有兩個從 master 分支上的 Commit 出去的兩個分支,分別是 one 分支與 two 分支。並且都比 master 領先兩個版本。

https://ithelp.ithome.com.tw/upload/images/20211005/20141010nhDoXrog1D.png

https://ithelp.ithome.com.tw/upload/images/20211005/20141010owi7MVvVgw.png

https://ithelp.ithome.com.tw/upload/images/20211005/20141010S6k9VJYpUn.png

👉 情況:使用 git rebase 指令來執行 one 分支合併 two 分支

// 確認當前位於 one 分支上
$ git rebase two # 合併 two 分支

https://ithelp.ithome.com.tw/upload/images/20211005/20141010O78Vf8O92L.png

使用 git log 指令查看現在分支與 Commit 的關係:

https://ithelp.ithome.com.tw/upload/images/20211005/20141010MaKspKDXTM.png

可以發現到本來 two 分支上的 Commit 的 SHA-1 值改變了。
3793657f562c
0807ce9e0cd0

這過程中是做了哪些事呢?我們可以一一拆解

A1 這個 Commit 要接到 two 分支上的 B1 Commit 上,因為 A1 先前的 Commit 基準點改變了,因此需要重新計算 A1 的 SHA-1 值,就會產生新的 Commit 物件 B1 。

https://ithelp.ithome.com.tw/upload/images/20211005/20141010tyv3g0SN3s.png

https://ithelp.ithome.com.tw/upload/images/20211005/2014101034g4ugMiGg.png

而原本接著 A1 的 A2 Commit ,要接到 two 分支上時,原先的 A1 已變成 B1 ,Commit 的 SHA-1 值被改變了,因此 A2 這個 Commit 也需要重新計算新的 SHA-1 值,而產生新的 Commit 物件。

https://ithelp.ithome.com.tw/upload/images/20211005/20141010XucNY2rX4H.png

最後,原本 one 分支指向的 A2 這個 Commit 會改成 B2 這個 Commit 上。

https://ithelp.ithome.com.tw/upload/images/20211005/20141010Tk0bJd0zRf.png

上述計算的過程,在我們執行 git rebase 指令後得到的回饋也有顯示:Applying

https://ithelp.ithome.com.tw/upload/images/20211005/20141010FHItRFhVQN.png

意思就是說 git 在重新計算這個 Commit 的 SHA-1 值。

補充|那原本的 Commit 會不見嗎?答案是不會的,這些 Commit 依然存在,只是沒有一個分支指向他們。一段時間後,就會透過 Git 的資源回收機制回收走了。

同樣地,我們可以思考 git rebase 指令中誰合併誰會有差異嗎?

如果以最終結果來看,誰合併誰並沒有差異,但過程中的歷史紀錄會有差別喔!


如何取消 rebase ?

方法|

  1. git reflog → git reset --hard
  2. git reset ORIG_HEAD --hard

因為使用 git rebase 指令會導致 Commit 的 SHA-1 值改變,就不能透過 git reset HEAD^--hard 的方式回到合併前的狀態。

如果使用 git reset HEAD^--hard 指令,只會拆解最後一個 Commit 而已。

  1. Reflog |使用 Reflog 查看紀錄找回我們執行 rebase 指令時的 SHA-1 值。

    $ git reflog # 查詢變更軌跡
    

    https://ithelp.ithome.com.tw/upload/images/20211005/2014101047v6Od21fn.png

    https://ithelp.ithome.com.tw/upload/images/20211005/20141010nytYyjqZom.png

    找到相對應的 SHA-1 值後,可以執行以下指令回到當時的狀態。

    $ git reset [指定的 SHA-1 值] --hard # 還原指定的 Commit 狀態
    

    https://ithelp.ithome.com.tw/upload/images/20211005/20141010Zy9bJtlXvB.png

    如此一來就可以回到執行 git rebase 指令前的狀態囉!

  2. ORIG_HEAD

    ORIG_HEAD 會紀錄「危險操作」之前的 HEAD 位置。

    $ git reset ORIG_HEAD --hard
    

    https://ithelp.ithome.com.tw/upload/images/20211005/20141010oMyA1Afvak.png

👉 補充|什麼是 ORIG_HEAD

.git 目錄裡除了有 HEAD 檔案,也有一個叫做 ORIG_HEAD 的檔案。在這檔案裡會紀錄「危險操作」之前的 HEAD 位置。

什麼是危險操作?舉凡執行 mergerebasereset 這些指令有可能造成歷史紀錄的變動的動作,那麼在執行之前 HEAD 的狀態有可能被記錄在 ORIG_HEAD 的檔案裡。


Rebase 的使用時機

使用 rebase 的優勢

  1. 不會產生額外專用合併的 Commit
  2. 歷史順序可以依照誰 Rebase 誰來決定。

缺點:相較一般的合併來得沒那麼直覺。

上述有提到 rebase 等於是修改歷史,因此要避免修改已經推出去的歷史,否則會帶給合作者的困擾。

👉 對於已經推出去的內容,非必要情況時避免使用 Rebase 。


參考文章:https://www.maxlist.xyz/2020/05/02/git-merge-rebase/


上一篇
Day21|【Git】合併分支 git merge 指令 、快轉模式Fast Forward 、救回被砍掉的未合併分支方法
下一篇
Day23|【Git】各種合併衝突與分別解決方式
系列文
【Git】從零開始學習 Git - 30 天的學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言